/*--------------------- E X A M P L E   C O D E ---------------------------
 *
 * TITLE:       AT89LP Memory Access Routines
 *
 * FILE:        mem_access.c
 * VERSION:     1.0
 * DATE:        2010/05/03
 * TARGET:      AT89LP828, AT89LP6440 or similar
 * COMPILER:    Keil C51
 *
 * SUPPORT:     mcu@atmel.com
 *
 * DESCRIPTION:
 *      This application note provides C language routines for accessing
 *      the different memory spaces in an AT89LP device.
 *
 *------------------------------------------------------------------------*/

sfr MEMCON = 0x96;
sfr AUXR = 0x8E;
sfr DPCF = 0xA2;

/*-D----------------------------------------------------------------------
 * Select target device
 *------------------------------------------------------------------------*/
#define LP6440		// enable for LP6440
//#define LP828		// enable for LP828

/*-D----------------------------------------------------------------------
 * Set up memory boundaries
 *------------------------------------------------------------------------*/
#ifdef LP6440
  #define ERAM_SIZE	4096
  #define FDAT_SIZE	8192
  #define ERAM_START	0
  #define FDAT_START	ERAM_START+ERAM_SIZE
  #define XRAM_START	FDAT_START+FDAT_SIZE
#else
  #ifdef LP828
    #define ERAM_SIZE	512
    #define FDAT_SIZE	1024
    #define ERAM_START	0
    #define FDAT_START	ERAM_START+ERAM_SIZE
    #define XRAM_START	FDAT_START+FDAT_SIZE
  #endif
#endif

/*-M----------------------------------------------------------------------
 * Example
 *------------------------------------------------------------------------*/
  unsigned char xdata my_edata[10] _at_ ERAM_START;
  unsigned char xdata my_fdata[10] _at_ FDAT_START;
  unsigned char xdata my_xdata[10] _at_ XRAM_START;
  unsigned char code my_code[10];
 
  unsigned char read_eram(unsigned char xdata *ptr);
  void write_eram(unsigned char xdata *ptr, unsigned char byte);
  unsigned char read_fdata(unsigned char xdata *ptr);
  void write_fdata(unsigned char xdata *ptr, unsigned char byte);
  unsigned char read_xram(unsigned char xdata *ptr);
  void write_xram(unsigned char xdata *ptr, unsigned char byte);
  unsigned char read_code(unsigned char code *ptr);
  void write_code(unsigned char xdata *ptr, unsigned char byte);
  unsigned char read_sig(unsigned char code *ptr);
  void write_sig(unsigned char xdata *ptr, unsigned char byte);

void main()
{ unsigned char tmp;
 unsigned char xdata *cptr;

  // write to ERAM
  write_eram(&my_edata[0], 0x55);

  // read from ERAM
  tmp = read_eram(&my_edata[0]);
  
  // write to FDATA
  write_fdata(&my_fdata[0], 0xAA);
  
  // read from FDATA
  tmp =	read_fdata(&my_fdata[0]);
  
  // write to XRAM
  write_xram(&my_xdata[0], 0x33);
  
  // read from XRAM
  tmp = read_xram(&my_xdata[0]);
  
  // write to CODE
  cptr = &my_code[0];
  write_code(cptr, 0x66); 
  
  // read from CODE
  tmp = read_code(&my_code[0]);

  while(1);
}
	
/*-F----------------------------------------------------------------------
 * function: read_eram
 * desciption: read a byte from internal extended RAM
 * parameters: 
 *     ptr - pointer to address in valid ERAM range
 * return value:
 *     data value
 *------------------------------------------------------------------------*/

unsigned char read_eram(unsigned char xdata *ptr)
{ unsigned char tmp;
  AUXR &= ~2;		// clear EXTRAM (omit if EXTRAM is never set)
  MEMCON &= ~0x80; 	// clear IAP (omit if IAP is never set)
  tmp = *ptr;
  return(tmp);
}

/*-F----------------------------------------------------------------------
 * function: write_eram
 * desciption: write a byte to internal extended RAM
 * parameters: 
 *     ptr - pointer to address in valid ERAM range
 *     byte  - data to write
 * return value:
 *     none
 *------------------------------------------------------------------------*/

void write_eram(unsigned char xdata *ptr, unsigned char byte)
{
  AUXR &= ~2; 		// clear EXTRAM (omit if EXTRAM is never set)
  MEMCON &= ~0x80; 	// clear IAP (omit if IAP is never set)
  *ptr = byte;
}

/*-F----------------------------------------------------------------------
 * function: read_fdata
 * desciption: read a byte from internal flash data
 * parameters: 
 *     ptr - pointer to address in valid FDATA range
 * return value:
 *     data value
 *------------------------------------------------------------------------*/

unsigned char read_fdata(unsigned char xdata *ptr)
{ unsigned char tmp;
  AUXR &= ~2; 		// clear EXTRAM (omit if EXTRAM is never set)
  MEMCON &= ~0x80; 	// clear IAP (omit if IAP is never set)
  MEMCON |= 8; 		// set DMEN
  tmp = *ptr;
  MEMCON &= ~8; 	// clear DMEN
  return(tmp);
}

/*-F----------------------------------------------------------------------
 * function: write_fdata
 * desciption: write a byte to internal flash data. Note that the CPU will
 *             idle for several milliseconds while the write completes. Also
 *             a page write of multiple bytes is preferred.
 * parameters: 
 *     ptr - pointer to address in valid FDATA range
 *     byte - data to write
 * return value:
 *     none
 *------------------------------------------------------------------------*/

void write_fdata(unsigned char xdata *ptr, unsigned char byte)
{
  AUXR &= ~2; 		// clear EXTRAM (omit if EXTRAM is never set)
  MEMCON &= ~0x80; 	// clear IAP (omit if IAP is never set)
  MEMCON &= ~0x20; 	// clear LDPG (omit if LDPG is never set)
  MEMCON |= 0x18; 	// set DMEN and MWEN
  *ptr = byte;
  MEMCON &= ~0x18; 	// clear DMEN and MWEN
}

/*-F----------------------------------------------------------------------
 * function: read_xram
 * desciption: read a byte from external RAM
 * parameters: 
 *     ptr - pointer to address in valid XRAM range
 * return value:
 *     data value
 *------------------------------------------------------------------------*/

unsigned char read_xram(unsigned char xdata *ptr)
{ unsigned char tmp;
  AUXR |= 2; 		// set EXTRAM (omit if address does not overlap ERAM or FDATA)
  MEMCON &= ~0x80; 	// clear IAP (omit if IAP is never set)
  tmp = *ptr;
  AUXR &= ~2; 		// clear EXTRAM (omit if not set above)
  return(tmp);
}

/*-F----------------------------------------------------------------------
 * function: write_xram
 * desciption: write a byte to external RAM
 * parameters: 
 *     ptr - pointer to address in valid XRAM range
 *     byte  - data to write
 * return value:
 *     none
 *------------------------------------------------------------------------*/

void write_xram(unsigned char xdata *ptr, unsigned char byte)
{
  AUXR |= 2; 		// set EXTRAM (omit if address does not overlap ERAM or FDATA)
  MEMCON &= ~0x80; 	// clear IAP (omit if IAP is never set)
  *ptr = byte;
  AUXR &= ~2; 		// clear EXTRAM (omit if not set above)
}

/*-F----------------------------------------------------------------------
 * function: read_code
 * desciption: read a byte from internal code flash
 * parameters: 
 *     ptr - pointer to address in valid CODE range
 * return value:
 *     data value
 *------------------------------------------------------------------------*/

unsigned char read_code(unsigned char code *ptr)
{ unsigned char tmp;
  DPCF &= ~8; 		// clear SIGEN (omit if SIGEN is never set)
  tmp = *ptr;
  return(tmp);
}

/*-F----------------------------------------------------------------------
 * function: write_code
 * desciption: write a byte to internal code flash. Note that the CPU will
 *             idle for several milliseconds while the write completes. Also
 *             a page write of multiple bytes is preferred.
 * parameters: 
 *     ptr - pointer to address in valid CODE range
 *     byte - data to write
 * return value:
 *     none
 *------------------------------------------------------------------------*/

void write_code(unsigned char xdata *ptr, unsigned char byte)
{
  DPCF &= ~8; 		// clear SIGEN (omit if SIGEN is never set)
  AUXR &= ~2; 		// clear EXTRAM (omit if EXTRAM is never set)
  MEMCON &= ~0x20; 	// clear LDPG (omit if LDPG is never set)
  MEMCON &= ~8; 	// clear DMEN (omit if DMEN is never set)
  MEMCON |= 0x90; 	// set MWEN and IAP
  *ptr = byte;
  MEMCON &= ~0x90; 	// clear MWEN and IAP
}

/*-F----------------------------------------------------------------------
 * function: read_sig
 * desciption: read a byte from internal signature array
 * parameters: 
 *     ptr - pointer to address in valid SIG range
 * return value:
 *     data value
 *------------------------------------------------------------------------*/

unsigned char read_sig(unsigned char code *ptr)
{ unsigned char tmp;
  DPCF |= 8; 		// set SIGEN
  tmp = *ptr;
  DPCF &= ~8; 		// clear SIGEN
  return(tmp);
}

/*-F----------------------------------------------------------------------
 * function: write_sig
 * desciption: write a byte to internal signature array. Note that the CPU 
 *             will idle for several milliseconds while the write completes. 
 *             Also a page write of multiple bytes is preferred.
 * parameters: 
 *     ptr - pointer to address in valid SIG range
 *     byte  - data to write
 * return value:
 *     none
 *------------------------------------------------------------------------*/

void write_sig(unsigned char xdata *ptr, unsigned char byte)
{
  AUXR &= ~2; 		// clear EXTRAM (omit if EXTRAM is never set)
  MEMCON &= ~0x20; 	// clear LDPG (omit if LDPG is never set)
  MEMCON &= ~8; 	// clear DMEN (omit if DMEN is never set)
  DPCF |= 8; 		// set SIGEN
  MEMCON |= 0x90; 	// set MWEN and IAP
  *ptr = byte;
  DPCF &= ~8; 		// clear SIGEN
  MEMCON &= ~0x90; 	// clear MWEN and IAP
}

